package com.nowcoder.community.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @BelongsProject: community
 * @BelongsPackage: com.nowcoder.community.aspect
 * @Author: Master_XXJS
 * @CreateTime: 2023-01-03  14:10
 * @Description: TODO
 * @Version: 1.0
 */
@Component
@Aspect
public class ServiceLogAspect {
    private static final Logger logger = LoggerFactory.getLogger(ServiceLogAspect.class);

    //* 返回值（接受所有的返回值）
    //* service 下面的所有的 service 类
    //** service类中的 所有的方法
    //(..) service类中的所有方法的 全部的参数 都能接受
    @Pointcut("execution(* com.nowcoder.community.service.*.*(..))")
    public void pointcut() {

    }

    /**
     * 需求：
     *      在执行方法之前，记录日志   用户[xxx.xxx.xxx(IP地址)],在[xxx（时间）],访问了[com.nowcoder.community.service.xxx()].
     * @param joinPoint 一般这些的 JoinPoint 其实就是 service 中准备执行的那个方法
     */
    @Before("pointcut()")
    public void before(JoinPoint joinPoint) {
        //获取 请求方 的 主机的ip地址
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        //这个只有调用 controller 才会有请求，然而这个是 只要调用了 service 就会捕抓
        //一般我们都是 controller 里面调用 service
        //但是，kafka 中的消费者不是controller ，也进行调用了 service，被捕抓了，但是 kafka 的调用没有 request 请求（controller）
        //所以下面会报空指针异常
        if (attributes == null){
            return;
        }
        HttpServletRequest request = attributes.getRequest();
        String ip = request.getRemoteHost();
        //当前请求的时间
        String now = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        //访问的方法（接口）进行拼接，signature 签名
        // 代码意思：　类名　+　方法名
        String target = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();

        //进行记录日志（控制台）
        logger.info(String.format("用户[%s],在[%s],访问了[%s].", ip, now, target));
    }
}

